<?php


namespace App\Services;

use App\Models\PartCompany;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use OSS\Core\OssException;
use OSS\OssClient;
use PHPUnit\Util\Exception;

/**
 * Class AttachmentService
 * @package App\Services
 * 文件上传到本地服务器 （有些文件需要下载，放到本地方便下载）
 * 如果访问file地址，404，删除public下面的storage和 storage下面的public然后执行  php artisan storage:link 重新生成
 */
class AttachmentService
{
    protected $maxSize;
    protected $accessKeyId;
    protected $accessKeySecret;
    protected $endpoint;
    protected $bucket;
    protected $ossClient;

    public function __construct()
    {
        $config = SystemConfigService::getInfo(); //获取系统配置 (项目要求把配置文件存放到数据库，而不是 .env文件)

        $this->maxSize         = 2000 * 1024 * 1024;
        $this->bucket          = $config['bucket'];
        $this->endpoint        = $config['endpoint'];
        $this->accessKeyId     = $config['oss_access_key'];
        $this->accessKeySecret = $config['oss_access_secret'];

        $this->ossClient = new OssClient($this->accessKeyId, $this->accessKeySecret, $this->endpoint);
    }

    /**
     * 单个文件上传
     *
     * @param $file
     * @param string $saveType
     * @param int $partCompanyId
     * @param int $projectClassifyId
     * @param string $type
     * @return array
     * @throws \OSS\Http\RequestCore_Exception
     * @author: lxk
     * @date: 2024-12-13 13:58
     */
    public function upload($file, string $saveType = 'oss', int $partCompanyId = 0, int $projectClassifyId = 0, string $type = 'paper'): array
    {
        if ($file === null) {
            throw new Exception('文件不能为空');
        }
        if (!$file->isValid()) {
            throw new Exception('文件不合法');
        }
        $fileSize = $file->getSize();
        if ($fileSize > $this->maxSize) {
            throw new Exception('文件过大');
        }
        $tmpFile      = $file->getRealPath(); //获取上传图片的临时地址
        $originalName = $file->getClientOriginalName(); //获取原文件名
        $ext          = $file->getClientOriginalExtension(); //获取文件后缀名
        $folder       = $this->getFolder($ext);
        $md5FileName  = md5($originalName . time()) . '.' . $ext; //md5加密处理
        $projectId    = PartCompany::query()->where('id', $partCompanyId)->value('project_id');

        $pathName = "{$folder}/pro{$projectId}/part{$partCompanyId}/unitPro{$projectClassifyId}/$md5FileName";
        if ($type == 'photo') {
            $pathName = "{$folder}/pro{$projectId}/part{$partCompanyId}/photoUnitPro{$projectClassifyId}/$md5FileName";
        }
        if (config('site.domain') != 'https://tielu.qichenglantai.com/') {  //如果是测试（便于删除没用的oss文件）
            $pathName = 'test/' . $pathName;
        }
        $data['file_ext']    = $ext;
        $data['base_url']    = '';
        $data['file_size']   = round($fileSize / 1024); //把byte转化为KB
        $data['origin_name'] = substr($originalName, 0, strripos($originalName, '.')); //去掉原文件名后缀.pdf
        if ($saveType == 'local') { //存到本地
            Storage::disk('public')->put($pathName, file_get_contents($tmpFile));
            $data['file']     = $pathName; //获取文件存储的路径
            $data['base_url'] = config('site.domain') . 'storage/';
        } else {
            try { //存到OSS
                $option = ['Content-Disposition' => 'inline'];
                $result = $this->ossClient->uploadFile($this->bucket, $pathName, $tmpFile, $option); //OSS上传并获取返回结果
                $ossUrl = $result['info']['url'];
                if (!str_contains($ossUrl, 'https')) { //如果不是https
                    $ossUrl = str_replace('http', 'https', $ossUrl); //把http转化为https
                }
                $data['file'] = $ossUrl;
            } catch (OssException $e) {
                throw new Exception($e->getMessage());
            }
        }

        return $data;
    }

    /**
     * 判断OSS对象是否存在
     *
     * @param $object
     * @return bool|null
     * @throws OssException
     * @throws \OSS\Http\RequestCore_Exception
     * @author: lxk
     * @date: 2024/4/17 17:32
     */
    public function doesObjectExeist($object)
    {
        return $this->ossClient->doesObjectExist($this->bucket, $object);
    }

    /**
     * 获取OSS对象的大小
     * $object: pdfs/20240417/675f53f058f6cf1d0330c703910e95a4.pdf
     */
    public function getOssObjectSize($object)
    {
        $meta = $this->ossClient->getSimplifiedObjectMeta($this->bucket, $object);

        return round($meta['content-length'] / 1024); //把byte转化为KB
    }

    /**
     * 删除文件
     * $fileUrl : 'https://tieluoss.oss-cn-chengdu.aliyuncs.com/pdfs/20230519/1b4316c8f325792ef26dbadb6295f4b0.pdf';
     * $object  ： pdfs/20230519/1b4316c8f325792ef26dbadb6295f4b0.pdf
     */
    public function delOssFile($fileUrl)
    {
        $pos    = strpos($fileUrl, '.com');
        $object = substr($fileUrl, $pos + 5);

        $this->ossClient->deleteObject($this->bucket, $object);
    }

    /**
     * 根据附件后缀，返回需要的文件夹名
     */
    public static function getFolder($ext)
    {
        if (in_array($ext, ['xls', 'xlsx'])) {
            return 'excels';
        } elseif (in_array($ext, ['doc', 'docx'])) {
            return 'words';
        } elseif (in_array($ext, ['pdf'])) {
            return 'pdfs';
        } elseif (in_array($ext, ['png', 'jpg', 'jpeg', 'gif'])) {
            return 'images';
        } else {
            return $ext . 's';
        }
    }

    /**
     * 下载oss文件，并重新命名
     * 上传到oss的文件名经过了md5加密，下载到电脑上希望能看到加密前的文件名
     * $fileUrl 这种格式： templates/20221010/b4de1b75bc75ccf5919466c0ea3fba23.xlsx
     */
    public function download($fileUrl, $newName)
    {
        $parseUrl  = parse_url($fileUrl);
        $fileUrl   = substr($parseUrl['path'], 1);
        $timeout   = 3600;
        $newName   = $newName . '.' . pathinfo($fileUrl, PATHINFO_EXTENSION); //必须带上文件后缀
        $newName   = rawurlencode($newName); //防止乱码
        $ossConfig = array($this->ossClient::OSS_SUB_RESOURCE => 'response-content-disposition=attachment%3Bfilename%3D' . $newName);
        try {
            $signedUrl = $this->ossClient->signUrl($this->bucket, $fileUrl, $timeout, $this->ossClient::OSS_HTTP_GET, $ossConfig);
        } catch (\OSS\Core\OssException $e) {
            ErrorMsgService::write($e, request()->url());
            return false;
        }

        return $signedUrl;
    }

    /**
     * 单纯的把OSS文件下载到本地指定位置
     * @author: lxk
     * @date: 2025-07-04 16:02
     */
    public function downloadOssToLocal($ossObject, $localPath, $pdfTable, $id)
    {
        if ($this->doesObjectExeist($ossObject)) {
            $localPath = storage_path("app/public/ossPdfs/{$localPath}");
            if (!file_exists(dirname($localPath))) {
                mkdir(dirname($localPath), 0755, true);
            }
            $options = array( // 下载文件
                OssClient::OSS_FILE_DOWNLOAD => $localPath,
            );
            $this->ossClient->getObject($this->bucket, $ossObject, $options);
            // 下载完成后的回调
            if (file_exists($localPath)) {
                info("文件下载完成: -----table---{$pdfTable}-----id={$id}");
                DB::table($pdfTable)->where('id', $id)->update(['is_local' => 1]);
                // 表里面有没有相关数据，没有的话新增一条
                if (!DB::table("pdf_update_results")->where('table_name', $pdfTable)->first()) {
                    DB::table("pdf_update_results")->insert(['table_name' => $pdfTable, 'start_time' => date('Y-m-d H:i:s')]);
                } else {
                    // 如果有数据，检测下PDF表是否更新完，如果更新完，结果表也更新下
                    if (!DB::table($pdfTable)->where('is_local', 0)->first()) { //如果都更新到本地了
                        DB::table("pdf_update_results")->where('table_name', $pdfTable)->update(['is_completed' => 1, 'end_time' => date('Y-m-d H:i:s')]);
                    }
                }
            }
        }
    }

}
